/*
 * @Description: 定义前端监控函数
 * @Author: 0001100986/LiuShuai
 * @Date: 2021-09-24 17:00:08
 * @LastEditTime: 2021-10-20 17:08:16
 * @LastEditors: 0001100986/LiuShuai
 */
import Vue from 'vue';
import $ from 'jquery';
import dayjs from 'dayjs';
import { menuData } from '@/mock/menuData.js';
import { baseUrl } from './config.js';
import { pathModel, detectDeviceType, networkSpeed, pagePerformance } from './utils';
import { clientDB, selectIndex, updateKey, deleteKey } from '@/utils/indexDB';

// 监控数据上报请求头
const headers = {
  'Accept': 'application/json, text/plain, */*',
  'Content-Type': 'application/json;charset=UTF-8',
  'internal-access-token': 'XlEvb2/N7JdjCo9xjxV8RLQOFCiNAu86UEjV0c+u2Rbu7MYc1GGlZq2xRiyVHsqWM1onU5/Dc/0Ueb5qk9bN63d2kwZXe9s01gVcVlzJZphL2SSazg21k2qF4DPiG3/kZpIWE1sv5NOKHStEpea3bPmKIbdfUWH7aVoq76HjN2wGSKlatvQTjjnSVVKh83yO158rSiEvcqQNY9qpnG837GqdhJ+AgosF+4pvHrQm8TxZzD23vtOn0wnfXAxTSrQNmA6NOAUZDmZTE/uEw+8LHV0S/nlieL2wLCNPE5LPCNz8GIs4khwpXw==',
  'Accept-Language': 'zh-cn'
};

export function webMonitor () {
  return {
    // IP
    // eslint-disable-next-line no-undef
    logId: typeof (returnCitySN) !== 'undefined' ? returnCitySN["cip"] : '127.0.0.1',
    // 所属用户
    // eslint-disable-next-line no-undef
    uuid: localStorage.getItem('sys') ? JSON.parse(localStorage.getItem('sys')).user.info.id : '-',
    // 日志类型
    logType: 'info',
    // 终端信息
    isTrusted: detectDeviceType(),
    // 页面路由
    msg: pathModel(window.location.href, menuData) ? pathModel(window.location.href, menuData) : '登录',
    // 浏览器信息
    userAgent: navigator.userAgent,
    // 页面URL
    path: window.location.href.indexOf('?') > -1 ? window.location.href.substring(window.location.href.lastIndexOf('#') + 1, window.location.href.lastIndexOf('?')) : window.location.href.substring(window.location.href.lastIndexOf('#') + 1, window.location.href.length),
    // 日志级别
    level: 'info',
    // 当前日期
    timeLocalString: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    // 当前时间
    time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    // 网络速率
    spendTime: networkSpeed(),
    // 性能参数
    performance: pagePerformance(),
  };
}

// 页面路径
export function pagePath (path) {
  let params = webMonitor();
  params.logType = 'path';
  report(params);
}

// Http请求信息
export function httpXhr (type, data) {
  if (type === 'info') {
    let params = webMonitor();
    params.logType = 'error';
    // 错误等级
    params.level = 'info';
    // 错误类型
    params.errorType = 'xhr';
    // 状态码
    params.code = data.status;
    // 请求URL
    params.requestUrl = data.config.url;
    // 请求方式
    params.method = data.config.method;
    // 请求体
    params.requestBody = JSON.stringify(data.config.data);
    // 返回结果集
    params.response = 'Success';
    // 返回
    params.messages = data.data.errorMsg;
    report(params);
  }
  if (type === 'normal') {
    let params = webMonitor();
    params.logType = 'normal';
    // 状态码
    params.code = data.status;
    // 请求URL
    params.requestUrl = data.config.url;
    // 请求方式
    params.method = data.config.method;
    // 请求体
    params.requestBody = JSON.stringify(data.config.data);
    // 返回结果集
    params.response = 'Success';
    // 返回
    params.messages = '请求成功';
    report(params);
  }
  if (type === 'error') {
    let params = webMonitor();
    params.logType = 'error';
    // 错误等级
    params.level = 'error';
    // 错误类型
    params.errorType = 'xhr';
    // 异常信息
    params.error = JSON.stringify(data);
    // 状态码
    params.code = data.response.status;
    // 请求URL
    params.requestUrl = data.config.url;
    // 请求方式
    params.method = data.config.method;
    // 请求体
    params.requestBody = JSON.stringify(data.config.data);
    // 返回结果集
    params.response = 'Error';
    let message = '';
    switch (data.response.status) {
      case 400:
        message = '错误请求';
        break;
      case 401:
        message = typeof data.response.data === 'string' ? data.response.data : '未授权，请重新登录！';
        break;
      case 403:
        message = '拒绝访问';
        break;
      case 404:
        message = '请求错误,未找到该资源！';
        break;
      case 405:
        message = '请求方法未允许';
        break;
      case 408:
        message = '请求超时';
        break;
      case 500:
        message = typeof data.response.data.error.debugMessage === 'string' ? data.response.data.error.debugMessage : '服务器端出错';
        break;
      case 501:
        message = '网络未实现';
        break;
      case 502:
        message = '网络错误';
        break;
      case 503:
        message = '服务不可用';
        break;
      case 504:
        message = '网络超时';
        break;
      case 505:
        message = 'http版本不支持该请求';
        break;
      default:
        message = `连接错误${data.response.status}`;
    }
    params.messages = message;
    report(params);
  }
}
// 错误监控
export function monitor () {
  // 资源加载错误
  window.addEventListener('error', (event) => {
    let target = event.target || event.srcElement;
    let message = "加载 " + target.tagName + " 资源错误";
    let params = webMonitor();
    params.logType = 'error';
    // 错误等级
    params.level = 'warn';
    // 错误类型
    params.errorType = 'resources';
    // 异常信息
    params.error = JSON.stringify(event);
    // 返回信息
    params.messages = message;
    report(params);
  });
  // 前端会话交互，重置倒计时
  document.addEventListener('click', async (e) => {
    let url = window.location.href;
    // 非登录页
    if (url.indexOf('login') === -1) {
      let time = await $.ajax({ url: baseUrl + '/api/sys/option/value/SYSTEM.SESSION.TIMEOUT', type: 'get' });
      let outTime = time * 60;
      localStorage.setItem('SYSTEM.SESSION.TIMEOUT', outTime);
    }
  });
  // 前端会话交互，监听键盘输入
  document.onkeydown = async (event) => {
    // eslint-disable-next-line no-caller
    let e = event || window.event || arguments.callee.arguments[0];
    let url = window.location.href;
    // 非登录页
    if (url.indexOf('login') === -1) {
      // 仅监听 Enter 键
      if (e && e.keyCode === 13) {
        let time = await $.ajax({ url: baseUrl + '/api/sys/option/value/SYSTEM.SESSION.TIMEOUT', type: 'get' });
        let outTime = time * 60;
        localStorage.setItem('SYSTEM.SESSION.TIMEOUT', outTime);
      }
    }
  };
  // JS错误
  window.onerror = (msg, url, line, col, error) => {
    let params = webMonitor();
    params.logType = 'error';
    // 错误等级
    params.level = 'warn';
    // 错误类型
    params.errorType = 'javascript';
    // 请求URL
    params.requestUrl = url;
    // 异常信息
    params.error = JSON.stringify(error);
    // 错误行号
    params.lineNo = line;
    // 错误列数
    params.columnNo = col;
    // 返回信息
    params.messages = msg;
    report(params);
  };

  // Vue异常
  Vue.config.errorHandler = (error, vm, info) => {
    let metaData = {
      message: error.message,
      stack: error.stack,
      info: info,
    };
    if (Object.prototype.toString.call(vm) === '[object Object]') {
      metaData.componentName = vm._isVue ? vm.$options.name || vm.$options._componentTag : vm.name;
      metaData.propsData = vm.$options.propsData;
    }
    let messge = JSON.stringify(metaData);
    let params = webMonitor();
    params.logType = 'error';
    // 错误等级
    params.level = 'error';
    // 错误类型
    params.errorType = 'vue';
    // 异常信息
    params.error = JSON.stringify(error);
    // 返回信息
    params.messages = messge;
    report(params);
  };
}

// 数据上报
function report (params) {
  // 连接数据库并写入
  clientDB('ione_db', 1, 'ione_table').then(db => {
    selectIndex(db, 'ione_table', "name", "Monitor").then(res => {
      let { status, data } = res;
      // 查询
      if (status === '0' && data) {
        // 每30次上报一次
        if (data.value.length >= 30) {
          $.ajax({
            url: baseUrl + '/api/sdwan/nbi/operations/v2/logdata/logreport',
            type: 'post',
            headers,
            data: JSON.stringify(data.value),
            success: () => {
              // 清空
              deleteKey(db, 'ione_table', 2);
              // 重置
              updateKey(db, 'ione_table', { id: 2, name: 'Monitor', value: [params] }, 2);
            },
            error: () => {
              // 本地存储
              data.value.push(params);
              updateKey(db, 'ione_table', data, 2);
            }
          });
        } else {
          // 本地存储
          data.value.push(params);
          updateKey(db, 'ione_table', data, 2);
        }
      } else {
        // 初始化
        updateKey(db, 'ione_table', { id: 2, name: 'Monitor', value: [params] }, 2);
      }
    });
  });
}